/*
 * R6.c
 *      Created on: Nov 20, 2013
 *              Authors: Joseph DeLong, Justin Hamric, Alex Newcomer, Alex Bouvy
 */

typedef struct param {
	int      op_code;
	int      device_id;
	char     *buf_p;
	int      *count_p;
} param;

#include <string.h>
#include <dos.h>
#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include "mpx_supt.h"
#include "defines.h"
#include "mpx_pcb.h"

#define SYS_STACK_SIZE 1024

//Hidden Commands
void carrot(char quality, int quantity);
void clear(void);
void alias(char* fname, char* newname, char** cnames);
//void logo(void);

//R1 Command Prototypes
int commhand(); //added struct MPX_Q's to be passed to ALL functions as needed
void date(char* input_tok[6], int command_args);
int help(int argc, char *argv[6], char** cnames);
int ls(char *input[6], int command_args);
int r_exit(int *exit);
void version(void);

//R2 Procedure Prototypes
MPX_PCB *allocPCB(void);
int freePCB(MPX_PCB *pcbName);
MPX_PCB *setupPCB(char processName[9], int processClass, int priority);
void insert_blocked(MPX_PCB* pcb);
void insert_ready(MPX_PCB* pcb);
int removePCB(struct MPX_PCB* pcbJ, int queue);
void show_all();
void disp();
void show_ready();
void show_blocked();
void show_pcb(struct MPX_PCB* pcb);
void blockPCB(char processName[9]);
void unblockPCB(char processName[9]);
MPX_PCB* find_ready(char processName[9]);
MPX_PCB* find_blocked(char processName[9]);

//suggested R2 commands
void R2Init(); //this will initialize our queues
void R2Clean(); //this will clear queues, reclaim all memory allocated to PCBs in them

//R3 Procedure Protypes
void interrupt sys_call();
void interrupt dispatcher();
void load_procs();

//R3 Test Prototypes
void test1_R3();
void test2_R3();
void test3_R3();
void test4_R3();
void test5_R3();

//R4 Protops
void load_program(char dirName[40], char programName[9], int priority);
void terminate_process(char processName[9]);

//r6 p
void R6Init();
void IOSched();

//GLOBALS
char prompt[255];
struct MPX_Q *ready, *blocked;
//G R3
unsigned char sys_stack[SYS_STACK_SIZE];
unsigned short new_ss = NULL;
unsigned short new_sp = NULL;
unsigned short ss_save = NULL;
unsigned short sp_save = NULL;
int iglobal;
int flagyyflaggedyflag = 0;
int whyreturnaninthere;
MPX_PCB *dummy;
MPX_PCB *cop;
param *param_ptr;
FILE *fptr;
unsigned char *testptr;

//R6
struct MPX_IOCB *termIOCB;
struct MPX_IOCB *comPortIOCB;
struct MPX_IOD *dummy1;

/*
 * MAIN function
 * This is the meat and potatoes of the Appaloosa OS. Everything gets run through here.
 * parameters: NOTHING
 * returns: Integer representing normal operation/termination (0) or an error code (non-zero)
 */
int main(void) {
	MPX_PCB *comhand, *idle;
	context* comhandC;
	sys_init(MODULE_F);
	R2Init(); //set up queues & allocate them memory
	R6Init();
	sys_set_vec(sys_call);
	//direct trm_open and com_open
	trm_open(&termIOCB->eventFlag); //give trm_open control of event flag
	//give com_open control of event flag
	com_open(&comPortIOCB->eventFlag, 1200); //1200 is the baud rate defined in slides
	strcpy(prompt,"$$>\0");
	//create commhand process
	comhand = sys_alloc_mem(sizeof(MPX_PCB));
	//initialize commhand PCB structure:
	comhand->stack_base = sys_alloc_mem(SYS_STACK_SIZE * 4);
	comhand->stack_top = comhand->stack_base + (SYS_STACK_SIZE * 4)-sizeof(context);
	strcpy(comhand->processName,"COMMHAND\0");
	comhand->processID = 0;
	comhand->processClass = 0; //system is 0, application is 1
	comhand->priority = 127; //highest priority
	comhand->pcb_state = READY;
	comhand->isSuspended = 0;
	comhand->memorySize = 4 * SYS_STACK_SIZE;
	//	pcb->load_address = (unsigned char*)sys_alloc_mem(prog_len_p);
	//	pcb->exec_address = pcb->load_address + start_offset_p;
	//	comhand->load_address = 0;
	//	comhand->exec_address = 0;
	comhand->next = NULL;
	comhand->prev = NULL;
	//create a CONTEXT for commhand
	comhandC = (context*) comhand->stack_top;
	comhandC->IP = FP_OFF(&commhand);
	comhandC->CS = FP_SEG(&commhand);
	comhandC->FLAGS = 0x200;
	comhandC->DS = _DS;
	comhandC->ES = _ES;
	insert_ready(comhand);
	//load IDLE
	load_program("./","IDLE",-128);
	//Make sure IDLE is designated a SYSTEM process
	idle = find_ready("IDLE");
	idle->processClass = 0; //system process
	//Resume it and put it in the ready queue
	idle->isSuspended = 0;
	dispatcher(); //continuous dispatch until EXIT is called
	/*
	 * THIS SHOULD BE WHERE WE DE-ALLOCATE ALL MEMORY BEFORE EXITING,
	 * AMONG OTHER THINGS
	 */
	//r6
	com_close(); //close com port
	trm_close(); //close terminal
	sys_free_mem(comhandC); //free COMMHAND's context
	sys_free_mem(comhand->stack_base); //free COMMHAND's stack
	sys_free_mem(comhand); //free COMMHAND itself
	idle->processClass = 1; //set idle's class to APPLICATION so we can call terminate_process()
	terminate_process(idle); //kill IDLE
	sys_free_mem(idle); //free IDLE itself
	//end r6
	//	R2Clean(); //empty queues & delete them
	//	sys_exit(); //quit!
	return 0; //THIS SHOULD ACTUALLY BE A DYNAMICALLY OBTAINED INTEGER AS ERROR CODES ARE/ARE NOT CAPTURED AND HANDLED
}

//---------------------------------------------------------R1 COMMANDS---------------------------------------------------------//

/*
 * COMMHAND
 * Written by Alex Bouvy
 * Command Handler for Appaloosa OS
 * parameters: NONE
 * returns: Integer representing normal termination (0), or an error code (non-zero)
 */
int commhand() {
	MPX_PCB* newpcb; //temp storage for creating, etc. PCBs
	int found; //flag indicating if a PCB was found
	char* cnames[40]; //string array for all our command names
	char input[256]; //imput buffer for getting input from the user
	char* input_tok[6]; //string array for holding up to 6 tokens: the command and up tp 5 parameters
	int bufferSize = 256; //max size of our input buffer
	int promptLength; //storage for length of prompt (used for change prompt function)
	int gallop = 1; //set this horse to moving!
	int stringSize; //COMPILER IS NOT CORRECT, THIS VARIABLE IS USED
	int command_args=0; //number of command arguments detected on input
	int max_args = 6; //maximum number of command arguments (including the command itself)
	int i;// counter variable used in for() loops, etc.
	int alphaFlag = 0;//falg used for detecting if an string is only alphabetical
	int whichQueue = 0;//indicator of which queue is to be processed (0=ready, 1=blocked)
	//------------comm literals----------------
	char c1[15]="ls\0";
	char c2[15]="date\0";
	char c3[15]="exit\0";
	char c4[15]="help\0";
	char c5[15]="version\0";
	char c6[15]="create-pcb\0";
	char c7[15]="delete-pcb\0";
	char c8[15]="block\0";
	char c9[15]="unblock\0";
	char c10[15]="suspend\0";
	char c11[15]="resume\0";
	char c12[15]="set-priority\0";
	char c13[15]="show-pcb\0";
	char c14[15]="show-all\0";
	char c15[15]="show-ready\0";
	char c16[15]="show-blocked\0";
	char c17[15]="alias\0";
	char c18[15]="load-procs\0";
	char c19[15]="dispatch\0";
	char d00[15]="mem\0";
	char d01[15]="qexit\0";
	char d02[15]="clear\0";
	char d03[15]="carrot\0";
	char d04[15]="disp\0";
	char d05[15]="lp\0";
	char d06[15]="whistle\0";
	char c20[15]="terminate\0";
	char c21[15]="go\0";
	char c22[15]="kill\0";
	cnames[0] = c1; //setting of command names into our command name array
	cnames[1] = c2;
	cnames[2] = c3;
	cnames[3] = c4;
	cnames[4] = c5;
	cnames[5] = c6;
	cnames[6] = c7;
	cnames[7] = c8;
	cnames[8] = c9;
	cnames[9] = c10;
	cnames[10] = c11;
	cnames[11] = c12;
	cnames[12] = c13;
	cnames[13] = c14;
	cnames[14] = c15;
	cnames[15] = c16;
	cnames[16] = c17;
	cnames[17] = c18;
	cnames[18] = c19;
	cnames[19] = d00;
	cnames[20] = d01;
	cnames[21] = d02;
	cnames[22] = d03;
	cnames[23] = d04;
	cnames[24] = d05;
	cnames[25] = c20;
	cnames[26] = d06;
	cnames[27] = c21;
	cnames[28] = c22;
	//------------/comm literals---------------
	logo();
	clear();
	//loop until user enters the exit command
	while(gallop) { //while still kicking up dust
		alphaFlag = 0;//clear this flag
		whichQueue = 0;//set queue to READY
		command_args=0;//reset this flag
		promptLength = strlen(prompt); //get length of the string used for prompt
		sys_req(2,1, prompt, &promptLength); //out put the prompt to the screen
		stringSize = sys_req(1, 1, input, &bufferSize); //get input from the user (after ENTER is pressed)
		bufferSize = 256;
		input_tok[0] = strtok(input," "); //tokenize the user input at every whitespace
		if(!strcmp(input_tok[0],"\n")){ //if the first token is just a carriage return
			continue; //skip all the rest
		}
		else{ //got good input
			for(i=1;i<max_args;i++){//iterate through max number of command args
				input_tok[i]=strtok(NULL," ");//tokenize each token
				if(input_tok[i]==NULL) break; //if token is empty, quit
				else command_args = i;//else keep counting number of tokens
			}
		}
		//hacky fix 1 for tokenization
		if(command_args==0){//if no command arguments present
			strxfrm(input_tok[0],input_tok[0], strlen(input_tok[0]));//do this to ensure string retains its information
			strcat(input_tok[0],"\0");//add a null terminator to the end
		}
		//hacky fix 2 for tokenization issue
		if(!(strcmp(input_tok[command_args],"\n"))){//if the last counted token is a carriage return
			input_tok[command_args] = NULL;//clear that last token
			command_args--;//indicate one less token
		}
		//command handling
		if(!(strcmp(input_tok[0],d00))) {//mem()
			printf("Core Left: %ld\n",coreleft());
		}
		else if(!(strcmp(input_tok[0],d01))) {//qexit
			gallop=0;
		}
		else if(!(strcmp(input_tok[0],d04))) {//disp
			disp();
		}
		else if(!(strcmp(input_tok[0],c1))) {//ls
			ls(input_tok, command_args);
		}
		else if(!(strcmp(input_tok[0],c2))){//date
			date(input_tok, command_args);
		}
		else if(!(strcmp(input_tok[0],c3))) {//r_exit
			if(command_args>0){
				printf("Command %s does not accept arguments.\n",c3);
			}
			else r_exit(&gallop);
		}
		else if(!(strcmp(input_tok[0],c4))) {//help
			help(command_args, input_tok,cnames);
		}
		else if(!(strcmp(input_tok[0],c5))) {//version
			if(command_args>0){
				printf("Command %s does not accept arguments.\n",c5);
			}
			else version();
		}
		//suspend
		else if(!(strcmp(input_tok[0],c10))) {
			input_tok[1][strlen(input_tok[1])-1] = '\0';
			if(command_args!=1){
				printf("Invalid number of arguments provided.\n");
			}else if(strlen(input_tok[1])>8){
				printf("The name of the PCB you wish to suspend must be 8 characters or less.\n");
			}else{
				newpcb = find_ready(input_tok[1]);
				if(newpcb == NULL) newpcb = find_blocked(input_tok[1]);
				if(newpcb != NULL){
					if(strcmp(newpcb->processName,"IDLE") != 0) {
						(*newpcb).isSuspended=1;
						printf("PCB '%s' suspended.\n",(*newpcb).processName);
					}else printf("Cannot suspend the IDLE process!\n");
				} else printf("PCB not found.\n");
			}
		}
		//resume
		else if(!(strcmp(input_tok[0],c11))) {
			input_tok[1][strlen(input_tok[1])-1] = '\0';
			if(command_args!=1){
				printf("Invalid number of arguments provided.\n");
			}else if(strlen(input_tok[1])>8){
				printf("The name of the PCB you wish to suspend must be 8 characters or less.\n");
			}else{
				newpcb = find_ready(input_tok[1]);
				if(newpcb == NULL) newpcb = find_blocked(input_tok[1]);
				if(newpcb != NULL){
					(*newpcb).isSuspended=0;
					printf("PCB '%s' resumed.\n",(*newpcb).processName);
				} else printf("PCB not found.\n");
			}
		}
		//set-priority
		else if(!(strcmp(input_tok[0],c12))) {
			if(command_args!=2){
				printf("Invalid number of arguments provided.\n");
			}
			else if(strlen(input_tok[1])>8){
				printf("The name of the PCB specified must be 8 characters or less.\n");
			}
			else if(atoi(input_tok[2])>127||atoi(input_tok[2])<-128){
				printf("Invalid priority specified.\n");
			}
			else if (strcmp(input_tok[1],"IDLE") == 1) printf("Cannot change the priority of the IDLE process!\n");
			else{
				for(i=0; i<strlen(input_tok[2]); i++){
					if(isalpha((input_tok[2])[i])){
						alphaFlag = 1;
					}
				}
				if(!alphaFlag){
					newpcb = find_ready(input_tok[1]);
					if(newpcb == NULL){
						newpcb = find_blocked(input_tok[1]);
						whichQueue = 1;
					}
					if(newpcb != NULL){
						(*newpcb).priority=atoi(input_tok[2]);
						if(!whichQueue){
							removePCB(newpcb, 1);
							insert_ready(newpcb);
						}
						printf("PCB '%s' priority changed.\n",(*newpcb).processName);
					} else printf("PCB not found.\n");
				}else printf("Invalid priority specified.\n");
			}
		}
		//show-pcb
		else if(!(strcmp(input_tok[0],c13))) {
			input_tok[1][strlen(input_tok[1])-1] = '\0';
			if(command_args!=1){
				printf("Invalid number of arguments provided.\n");
			}else if(strlen(input_tok[1])>8){
				printf("The name of the PCB you wish deleted must be 8 characters or less.\n");
			}else{
				newpcb = find_ready(input_tok[1]);
				if(newpcb == NULL) newpcb = find_blocked(input_tok[1]);
				if(newpcb != NULL){
					printf("Name: %s\n",(*newpcb).processName);
					printf("Class: %d\n",(*newpcb).processClass);
					printf("State: %d\n",(*newpcb).pcb_state);
					printf("Suspended: %d\n",(*newpcb).isSuspended);
					printf("Prio: %d\n",(*newpcb).priority);
				} else printf("PCB not found.\n");
			}
		}
		//show-all
		else if(!(strcmp(input_tok[0],c14))) {
			if(command_args>0){
				printf("Command %s does not accept arguments.\n",c14);
			}
			else {
				show_all();
			}
		}
		//show-ready
		else if(!(strcmp(input_tok[0],c15))) {
			if(command_args>0){
				printf("Command %s does not accept arguments.\n",c15);
			}
			else show_ready();
		}
		//show-blocked
		else if(!(strcmp(input_tok[0],c16))) {
			if(command_args>0){
				printf("Command %s does not accept arguments.\n",c16);
			}
			else show_blocked();
		}
		//alias
		else if(!(strcmp(input_tok[0],c17))) {
			if(command_args!=2){
				printf("Invalid number of arguments provided.\n");
			}
			else if(strlen(input_tok[2])>15){
				printf("New command name must be less than 15 characters.\n");
			}
			else alias(input_tok[1],input_tok[2],cnames);
		}
		else if(!(strcmp(input_tok[0],c20))) {//terminate process
			input_tok[1][strlen(input_tok[1])-1] = '\0';
			if(command_args!=1){
				printf("Invalid number of arguments provided.\n",c19);
			}
			else{
				terminate_process(input_tok[1]);
			}
		}
		else if(!(strcmp(input_tok[0],d02))) {//CLEAR SCREEN
			clear();
		}
		else if(!(strcmp(input_tok[0],d03))) {//CHANGE PROMPT
			if(input_tok[1] != NULL && input_tok[2] != NULL) { //if got 2 parameters
				i = strlen(input_tok[1]);
				if(i == 1) { //if parameter 1 is exactly one character
					if((input_tok[1][0] >= 65 && input_tok[1][0] < 91) || (input_tok[1][0] >= 97 && input_tok[1][0] < 123)) { //if parameter 1 is only A-Z or a-z
						for(i = 0; i < strlen(input_tok[2]) - 1; i++) { //look through all characters of parameter 2
							if(!isdigit(input_tok[2][i])) { //if current char is not a digit
								found = 0;
								break;
							}
							else { //parameter 2 is all digits
								found = 1;
							}
						}
						if(found) {
							i = strlen(input_tok[2]);
							input_tok[2][i - 1] = '\0';
							carrot(input_tok[1][0],atoi(input_tok[2]));
						}
						else {
							printf("Parameter 2 must be an integer only.\n");
						}
					}
					else {
						printf("Parameter 1 must be a single character only, whose value is A-Z.\n");
					}
				}
				else {
					printf("Parameter 1 must be a SINGLE character.\n");
				}
			}
			else {
				printf("This command must have two arguments: a single character and an integer.\n");
			}
		}
		//load-program
		else if (!(strcmp(input_tok[0], d05))){
			input_tok[3][strlen(input_tok[3])-1] = '\0';
			if(command_args!=3){
				printf("Invalid number of arguments provided.\n");
			}
			else if(isalpha(*input_tok[3])){
				printf("Priority provided must be an integer.\n");
			}
			else{
				printf("Loading Program\n");

				load_program(input_tok[1], input_tok[2],atoi(input_tok[3]));
				//load_program(char dirName[40], char programName[9], int priority
			}
		}
		else if(!(strcmp(input_tok[0], d06))) {//logo
			if(command_args > 1) {
				printf("You cannot whistle with anything but your lips. Try to use no parameters.\n");
			}
			else {
				logo();
				clear();
			}
		}
		else printf("Command '%s' not recognized\n",input_tok[0]);
	}
	R2Clean();//cleanup queues
	sys_req(EXIT, NO_DEV, NULL, NULL);//indicate system should exit
	return 0;
}

/* DATE function
 * Written by: Alex Newcomer
 * Command: date (-s yyyy mm dd)
 * If the command, date, is submitted to the terminal, the date is displayed.
 * If the command is submitted with the -s flag and an 8 digit number, if the date is valid, the system date will be set to the provided date
 * If the date submitted is not valid, a message will be sent to the terminal saying so.
 */
typedef struct date_record {
	int day;
	int month;
	int year;
} date_record;

void date(char* input_tok[6], int command_args){
	int i, j;
	int daysInFebruary;
	int foundACharacter = 0;
	date_record currentDate, newDate;
	if(command_args == 4){
		//error check
		if(abs((strncmp(input_tok[1], "-s", 2)))){
			// user entered invalid first arg
			printf("date -> First argument is an invalid switch.\n");
		} else if(!(strncmp(input_tok[1], "-s", 2))){
			//Alex's 9/19/2013 fixing the digit detection issue
			foundACharacter = 0;
			for(j=2; j < 5; j++){
				for(i=0; i < strlen(input_tok[j]); i++){
					if(isalpha(input_tok[j][i])){
						foundACharacter = 1;
					}
				}
			}
			if(foundACharacter){
				printf("date -> You must enter digits not characters.\n");
			}
			//end Alex 9/19/2013
			else if(atoi(input_tok[3]) > 12 || atoi(input_tok[3]) < 1){//check for yyyy(2) mm(3) dd(4), valid, not leapyear.
				//month too big
				printf("date -> too many months\n");
			} else {
				//months and years are OK, check valid days
				//if february
				if(atoi(input_tok[3]) == 2){
					int leap = 0;
					if(atoi(input_tok[2])%400 == 0){
						leap = 1;
					} else if (atoi(input_tok[2])%100 == 0){
						leap = 0;
					} else if(atoi(input_tok[2])%4 == 0){
						leap = 1;
					} else {
						leap = 0;
					}
					if(leap){
						daysInFebruary = 29;
					} else {
						daysInFebruary = 28;
					}
					if(atoi(input_tok[4]) <= daysInFebruary){
						//call date
						date(input_tok, command_args);
					} else {
						//exit with error (leap year)
						printf("date -> leap year violation\n");
					}
				} else {//not february
					switch(atoi(input_tok[3])){
					case 1: case 3: case 5: case 7: case 8: case 10: case 12:
						if((atoi(input_tok[4]) <= 31) && ( strlen(input_tok[2]) < 6) ){
							//set date
							newDate.month = atoi(input_tok[4]);
							newDate.year = atoi(input_tok[2]);
							newDate.day = atoi(input_tok[3]);
							sys_set_date(&newDate);
						} else {
							printf("date -> input error\n");
						}
						break;
					case 4: case 6: case 9: case 11:
						if(( atoi(input_tok[4]) <= 30 ) && ( strlen(input_tok[2]) < 6)){
							//set date
							newDate.month = atoi(input_tok[4]);
							newDate.year = atoi(input_tok[2]);
							newDate.day = atoi(input_tok[3]);
							sys_set_date(&newDate);
						} else {
							printf("date -> your days are invalid\n");
						}
						break;
					}
				}
			}
		}
		//date(input_tok, command_args);
	} else if(command_args != 0){
		printf("date -> You have entered the wrong number of arguments\n");
	} else { //no args, display the date!
		sys_get_date(&currentDate);
		printf("%d, %d, %d\n", currentDate.day, currentDate.month, currentDate.year);
	}
}

/*
 * HELP command function
 * Written by Joseph DeLong
 * parameter argc: Integer representing the number of command arguments passed in
 * parameter argv: Pointer to an array of character strings representing the specific command(s) the USER is requesting help for
 * returns 0 if all went well or another integer, depending on the appropriate error code
 */
int help(int argc, char *argv[6], char** cnames) {
	int returnVal = 0;
	if(argc < 1 || strcmp(argv[0],"\0") == 0) {
		printf( "You have invoked the HELP command. For more specific help, type HELP [CMD],\n"
				"where [CMD] is the command you would like help for.\n"
				"\n"
				"\tCommand\t| Brief Description\n"
				"________________|_______________________________________________________________"
				"%15s\t| Display/Set the current system date\n"
				"%15s\t| Exit the system\n"
				"%15s\t| Display the contents of the Present Working Directory\n"
				"%15s\t| Display the current version of the OS\n"
				"%15s\t| Shows the user-specified PCB & its internal guts\n"
				"%15s\t| Shows all PCBs currently in the READY state\n"
				"%15s\t| Shows all PCBs currently in the BLOCKED state\n"
				"%15s\t| Shows all PCBs\n"
				"%15s\t| Changes name of a command\n"
				"\n",cnames[1],cnames[2],cnames[0],cnames[4],cnames[12],cnames[14],cnames[15],cnames[13],cnames[16],cnames[24]);
	}
	else {
		argv[1][strlen(argv[1])-1] = '\0';
		//Secret / Extra Commands
		if(strcmp(argv[1],cnames[22]) == 0) {
			printf( "This has something to do with getting on Appaloosa's good side. Maybe she will\n"
					"let you ride her?\n");
		}
		else if(strcmp(argv[1],cnames[21]) == 0) {
			printf("This command clears the screen.\n");
		}
		//R1 Commands
		else if(strcmp(argv[1],cnames[1]) == 0) {
			printf( "To SHOW the current date, use date.\n"
					"To SET the system date, use date -s YYYY MM DD.\n"
					"You may enter negative years, indicating BCE.\n"
					"Months must be between 1 and 12.\n"
					"Days must not exceed their respective months.\n"
					"Leap year support is included.\n");
		}
		else if(strcmp(argv[1],cnames[2]) == 0) {
			printf( "This command will exit the Appaloosa OS. Make sure you have saved your work\n"
					"before exiting.\n");
		}
		else if(strcmp(argv[1], cnames[3]) == 0) {
			printf("Yes, this is the help command.\n");
		}
		else if(strcmp(argv[1],cnames[0]) == 0) {
			printf("This command displays the contents of the Current Directory.\n");
		}
		else if(strcmp(argv[1],cnames[4]) == 0) {
			printf( "This command shows the version and developer information for the current version\n"
					"of the Appaloosa OS.\n");
		}
		//R2 Commands
		else if(strcmp(argv[1], cnames[12]) == 0) {
			printf("This command will display the internal information contained\n"
					"in the specified PCB. It takes in 1 argument: The name of\n"
					"the PCB to be displayed.\n");
		}
		else if(strcmp(argv[1], cnames[13]) == 0) {
			printf( "This command displays information contained within all PCBs currently in the\n"
					"Ready Queue.\n");
		}
		else if(strcmp(argv[1], cnames[14]) == 0) {
			printf( "This command displays information contained within all PCBs currently in the\n"
					"Blocked Queue.\n");
		}
		else if(strcmp(argv[1], cnames[15]) == 0) {
			printf("This command displays information contained within all PCBs.\n");
		}
		else if(strcmp(argv[1], cnames[16]) == 0) {
			printf( "This command allows user to change the name of a given command to a name"
					"provided.\n");
		}
		else if(strcmp(argv[1], cnames[24]) == 0) {
			printf("This function loads programs from an external file.\n");
		}
		else {
			printf("You have requested help for a non-existent command: %s\n",argv[1]);
			returnVal = -56712; //placeholder for error code return (if we are going to do this)
		}
	}
	return returnVal;
}

/*
 * DIRECTORY function
 * Written by Justin Hamric
 * This function prints out the name and size (in bytes) of all files found in the current directory.
 */
int ls(char *input[6], int command_args) {
	char name_buf[40]; //can return a file name of length up to 40
	int buf_size = 40; //parameter that tells sys_get_entry how many characters can be returned
	long file_size_p; // size of returned file in bytes
	int i;
	int paginate = 0; //counts the number of lines printed at a time
	//char user_input[40];  
	if(command_args == 0) {
		sys_open_dir("\0"); //opens the current directory
		while(sys_get_entry(name_buf, buf_size, &file_size_p) != -113) {//while there's an entry
			if(paginate>20){//paginate if there is more than 20 lines returned
				printf("Press enter to proceed to the next page\n");
				getch();
				paginate = 0;
			}
			printf("%s of size %ld bytes.\n", name_buf, file_size_p); //prints file attributes
			paginate++;
		}
		sys_close_dir();  
	}else if(command_args == 1) { //if the user entered parameters
		input[1][strlen(input[1])-1] = '\0'; //replace carriage return with a null
		//printf("One Argument: %s  length: %d \n", input[1], strlen(input[1]));
		if(sys_open_dir(input[1])>=0) { //if directory was found
			while(sys_get_entry(name_buf, buf_size, &file_size_p) != -113) { //while entry remains
				if(paginate>20){
					printf("Press enter to proceed to the next page\n");
					getch();
					paginate = 0;
				}
				printf("%s of size %ld bytes.\n", name_buf, file_size_p);
				paginate++;
			}
		}else { //if directory wasn't found
			printf("The directory could not be found.\n");
		}
		sys_close_dir();
	}
	else {
		printf("Too many arguments.\n");
	}
	return 0;
}

/* EXIT function
 * Written by Alex Bouvy
 * parameter *exit: an integer pointer, which indicates whether this function ran correctly so MAIN can continue to system cleanup
 */
int r_exit(int *exit) {
	MPX_PCB *t;
	char question[19] = "Really exit? (y/n)\n";
	char input_buffer[256];
	char original_input[256];
	char* input[6];
	int qlength = 19;
	int bufferSize = 256;
	int i;
	int command_args = 0;
	sys_req(2,1, question, &qlength); //print question
	sys_req(1, 1, input_buffer, &bufferSize); //get answer to question
	bufferSize = 256;
	strcpy(original_input,input_buffer);
	strxfrm(original_input,original_input, strlen(original_input));
	input[0] = strtok(input_buffer," ");
	for(i=1;i<6;i++){
		input[i]=strtok(NULL," ");
		if(input[i]==NULL) break;
		else command_args = i;
	}
	if(strlen(input[0])>1){
		strxfrm(input[0],input[0], strlen(input[0]));
	}
	strcat(input[0],"\0");
	//hacky fix for other tokenization issue
	if(command_args==1){
		if(!(strcmp(input[1],"\n"))){
			command_args=0;
			input[1] = NULL;
		}
	}
	if(command_args>0){
		printf("'%s' is not valid.\n",original_input);
	}
	else if(!(strcmp(input[0],"Y\0"))) {
		*exit = 0;
	}
	else if(!(strcmp(input[0],"y\0"))) {
		*exit = 0;
	}
	else if(!(strcmp(input[0],"N\0"))) {
		//do nothing
	}
	else if(!(strcmp(input[0],"n\0"))) {
		//do nothing
	}
	else printf("'%s' is not valid.\n",input[0]);
	return 0;
}

/*
 * VERSION function
 * Written by Joseph DeLong
 * parameters: NONE
 * returns: NOTHING
 */
void version(void) {
	int size = sizeof(VERSION_INFO) - 1;
	sys_req(2, 1, VERSION_INFO, &size);// this info is held in defines.h
}
//--------------------------------------------------------/R1 COMMANDS---------------------------------------------------------//

//---------------------------------------------------------R2 COMMANDS---------------------------------------------------------//

/*
 * R2Init
 * Written by: Joseph DeLong and Alex J. Newcomer
 * Sets up Ready and Blocked queues for our PCBs to sit in
 * Also sets up the memory space for the Currently Operating Process (cop) and swap space variables for its stack pointer and stack segment
 */
void R2Init() {
	ready = sys_alloc_mem(sizeof(struct MPX_Q));
	blocked = sys_alloc_mem(sizeof(struct MPX_Q));
	(*ready).count = 0;
	(*ready).head = NULL;
	(*ready).tail = NULL;
	(*blocked).count = 0;
	(*blocked).head = NULL;
	(*blocked).tail = NULL;
	cop = sys_alloc_mem(sizeof(struct MPX_PCB));
	sp_save = NULL;
	ss_save = NULL;
	new_ss = NULL;
	new_sp = NULL;
}

/*
 * R2Clean Function
 * Written by: Joseph DeLong and Alex J. Newcomer
 * Calls deletePCB()(which frees the pcb's) for all and then frees the queues
 * NOTE: This should be checked with the mem function
 */
void R2Clean() {
	int i;
	MPX_PCB *temp = (*ready).head;
	MPX_PCB *temp1;
	//clear ready
	for(i = 0; i < (*ready).count; i++) {
		temp1 = (*temp).next;
		freePCB(temp);
		temp = temp1;
	}
	//clear blocked
	temp = (*blocked).head;
	for(i = 0; i < (*blocked).count; i++) {
		temp1 = (*temp).next;
		freePCB(temp);
		temp = temp1;
	}
	sys_free_mem(ready);
	sys_free_mem(blocked);
	sys_exit();
}

/* Alex Bouvy
 * freePCB()
 * Uses the support function sys_free_mem to free all the memory associated with a pcb
 *      Params:
 *      Pointer to pcb to free
 *      Returns:
 *      Nothing OR error/success code
 */
int freePCB(MPX_PCB* pcb){
	return sys_free_mem(pcb);
}

/* Alex Bouvy
 * allocPCB()
 * Uses the support function sys_alloc_mem(0 to allocate memory for a PCB
 * Returns:
 *      Pointer to the PCB if successful
 *      NULL if error, including if one of the parameters is invalid
 */
MPX_PCB *allocPCB(){
	MPX_PCB* p;
	p = sys_alloc_mem(sizeof(MPX_PCB));
	return p;
}

/* Alex Bouvy
 * SetupPCB()
 * Procedures: Setup-PCB 19/32
 * CS 450 LAB Module R2 Feb. 1, 2013
 * Initializes the information in your PCB structure. Does not
 * insert into a queue. Calls Allocate-PCB(), sets state to
 * ready, not suspended (this will change later)
 * Parameters: Process Name, class, priority
 * Returns:
 *      Pointer to the PCB if successful
 *      NULL if error, including if one of the parameters is invalid
 */
MPX_PCB* setupPCB(char procName[9], int processClass, int prio) {
	MPX_PCB* pcb;
	//initialize PCB structure:
	pcb = allocPCB();
	pcb->stack_base = sys_alloc_mem(SYS_STACK_SIZE);
	pcb->stack_top = pcb->stack_base + SYS_STACK_SIZE-sizeof(context);
	strcpy((*pcb).processName,procName);
	strcat((*pcb).processName,"\0");
	(*pcb).processID = 0;
	(*pcb).processClass = processClass; //system is 0, application is 1
	(*pcb).priority = prio;
	(*pcb).pcb_state = 1;
	(*pcb).isSuspended = 1;
	(*pcb).memorySize;
	(*pcb).load_address = 0;
	(*pcb).exec_address = 0;
	return pcb;
}

/*
 * CLEAR SCREEN function
 *  Created on: Sep 12, 2013
 *      Author: Joseph DeLong
 * parameters: NONE
 * returns: Nothing.
 */
void clear(void) {
	sys_req(3,1,((void *)0),((void *)0)); //CLEAR(3) the TERMINAL(1)
}

/*
 * CHANGE PROMPT function
 * Author: Joseph DeLong
 * Allows the user to feed the friendly Appaloosa. In return, she will accept any name you give her.
 * parameter QUALITY: A character representing the quality of the carrot offered to Appaloosa. Quality values are:
 *
 *              VALUE                   | QUALITY POINTS
 *              --------------------|---------------
 *              A(awful)                |       -10
 *              B(bitter)                       |       -5
 *              C(crisp)                        |       +5
 *              D(dirty)                        |       0
 *              E(erroneous)        |   -1
 *              F(flimsy)               |       -2
 *              G(good)                 |       +10
 *              H(horrible)             |       -11
 *              I(ideal)                |       +25
 *              J(just right)       |   +15
 *              K(killer)               |       +18
 *              L(lousy)                |       -7
 *              M(moldy)                |       -4
 *              N(normal)               |       +3
 *              O(orange)               |       +1
 *              P(poor)                 |       -4
 *              Q(quick)                |       +13
 *              R(rotten)               |       -17
 *              S(sweet)                |       +13
 *              T(tasty)                |       +8
 *              U(ugly)                 |       -4
 *              V(violent)              |       -9
 *              W(wobbly)               |       -2
 *              X(x-ray)                |       +7
 *              Y(yellow)               |       +1
 *              Z(zebra)                |       +3
 *
 * parameter QUANTITY: Integer representing the number of carrots offered to old faithful Appaloosa.
 * returns: Pointer to character string containing the new name Appaloosa accepts commands by.
 */
void carrot(char quality, int quantity) {
	char value[26] = {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
	int worth[26] = {-10,-5,5,0,-1,-2,10,-11,25,15,18,-7,-4,3,1,-4,13,-17,13,8,-4,-9,-2,7,1,3};
	int i;
	for(i = 0; i < 26; i++) {
		if(value[i] == toupper(quality)) {
			if(worth[i] * quantity >= 100) {
				//allow change
				printf( "Appaloosa accepts your gracious gift of CARROT. What should her new PROMPT be?\n");
				i = 255;
				sys_req(1,1, prompt, &i); //get input from user
				for(i = 0; i < strlen(prompt); i++) {
					if(prompt[i] == '\n') {
						prompt[i] = '\0';
						break;
					}
					else if(i == strlen(prompt) - 1) {
						prompt[i] = '\0';
						break;
					}
				}
				break;
			}
			else {
				//disallow change
				printf("Appaloosa turns her head away. Your gift of CARROT is sub-par at best.\n");
				break;
			}
		}
	}
}//have a nice day!

/* Alex Bouvy
 * show_ready()
 * 	This function displays all PCBs currently residing in the READY queue, in priority order.
 */
void show_ready(){
	int index;
	MPX_PCB* temp;
	int paginate = 0;
	int queueCurrent = 1;
	clear();
	printf("\n");
	printf("Ready Queue:\n\n");
	paginate = paginate + 3;
	temp = (*ready).head;
	for(index = 0; index<(*ready).count; index++){
		if(paginate>18){
			printf("Press enter to proceed to the next page\n\n");
			getchar();
			paginate = 0;
			clear();
		}
		printf("Name: %s\n",(*temp).processName);
		printf("Class: %d\n",(*temp).processClass);
		printf("State: %d\n",(*temp).pcb_state);
		printf("Suspended: %d\n",(*temp).isSuspended);
		printf("Prio: %d\n",(*temp).priority);
		printf("\n");
		paginate = paginate +6;
		temp = (*temp).next;
	}
	printf("\n");
	sleep(1);
	printf("Press enter to proceed to the next page\n\n");
	getchar();
	clear();
}

/* Alex Bouvy
 * show_blocked()
 * 	This function displays all PCBs currently residing in the BLOCKED queue, in FIFO order.
 */
void show_blocked(){
	int index;
	MPX_PCB* temp;
	int paginate = 0;
	int queueCurrent = 1;
	clear();
	printf("\n");
	printf("Blocked Queue:\n\n");
	paginate = paginate + 3;
	temp = (*blocked).head;
	for(index = 0; index<(*blocked).count; index++){
		if(paginate>18){
			printf("Press enter to proceed to the next page\n\n");
			getchar();
			paginate = 0;
			clear();
		}
		printf("Name: %s\n",(*temp).processName);
		printf("Class: %d\n",(*temp).processClass);
		printf("State: %d\n",(*temp).pcb_state);
		printf("Suspended: %d\n",(*temp).isSuspended);
		printf("Prio: %d\n",(*temp).priority);
		printf("\n");
		paginate = paginate + 6;
		temp = (*temp).next;
	}
	printf("\n");
	sleep(1);
	printf("Press enter to proceed to the next page\n\n");
	getchar();
	clear();
	printf("\n");
}

/* Alex Bouvy
 * disp()
 * 	This is a shortcut for quickly displaying all PCBs, in both the ready and blocked queues
 */
void disp(){
	int index;
	MPX_PCB* temp;
	printf("\n");
	printf("Ready Queue:\n");
	temp = (*ready).head;
	for(index = 0; index<(*ready).count; index++){
		printf("%s %d\n",(*temp).processName,(*temp).priority);
		temp = (*temp).next;
	}
	printf("\n");
	printf("Blocked Queue:\n");
	temp = (*blocked).head;
	for(index = 0; index<(*blocked).count; index++){
		printf("%s %d\n",(*temp).processName,(*temp).priority);
		temp = (*temp).next;
	}
	printf("\n");
}

/* Alex Bouvy
 * show_all()
 * 	This function displays all PCBs in first the Ready and then the Blocked queue.
 * 	It automatically paginates the information, promting the user to PRESS ENTER TO CONTINUE
 */
void show_all(){
	show_ready();
	show_blocked();
}

/* Alex Bouvy
 * insert_blocked()
 * 	This function inserts the specified PCB into the BLOCKED queue
 */
void insert_blocked(struct MPX_PCB* new) {
	int index;
	if((*blocked).count==0){
		(*blocked).head = new;
		(*blocked).tail = new;
		(*new).next = NULL;
		(*new).prev = NULL;
		(*blocked).count++;
	}
	else{
		(*(*blocked).tail).next = new;
		(*new).prev = (*blocked).tail;
		(*blocked).tail = new;
		(*blocked).count++;
	}
}

/* Alex Bouvy
 * insert_ready()
 * 	This function inserts the specified PCB into the READY queue
 */
void insert_ready(struct MPX_PCB* new) {
	int index;
	int prio = (*new).priority;
	MPX_PCB* temp;
	MPX_PCB* prev;
	if((*ready).count==0){
		(*ready).head = new;
		(*ready).tail = new;
		(*new).next = NULL;
		(*new).prev = NULL;
		(*ready).count++;
	}
	else if(prio>(*(*ready).head).priority){
		(*new).next = (*ready).head;
		(*(*ready).head).prev = new;
		(*ready).head = new;
		(*ready).count++;
	}
	else{
		temp = (*ready).head;
		for(index = 0; index<(*ready).count; index++){
			if((*new).priority>(*temp).priority){
				(*prev).next = new;
				(*new).prev = prev;
				(*new).next = temp;
				(*temp).prev = new;
				(*ready).count++;
				return;
			}
			prev = temp;
			temp = (*temp).next;
		}
		(*prev).next = new;
		(*ready).tail = new;
		(*new).prev = prev;
		(*ready).count++;
	}
}

/* Alex Bouvy
 * removePCB()
 * This function removes the specified PCB from its respective queue.
 * queue 1 = ready, 0 = blocked
 */
int removePCB(struct MPX_PCB* pcbJ, int queue){
	//pcbJ is head
	if(queue){
		if(!strcmp((*(*ready).head).processName,(*pcbJ).processName)){
			(*ready).head = (*(*ready).head).next;
			(*(*ready).head).prev = NULL;
		}
		//pcbJ is tail
		else if((*pcbJ).next == NULL){
			(*ready).tail = (*pcbJ).prev;
			(*(*ready).tail).next = NULL;
		}
		//pcbJ is in middle
		else{
			(*(*pcbJ).prev).next = (*pcbJ).next;
			(*(*pcbJ).next).prev = (*pcbJ).prev;
		}
		(*ready).count--;
		return 1;
	} else if(queue){
		if(!strcmp((*(*blocked).head).processName,(*pcbJ).processName)){
			(*blocked).head = (*(*blocked).head).next;
			(*(*blocked).head).prev = NULL;
		}
		//pcbJ is tail
		else if((*pcbJ).next == NULL){
			(*blocked).tail = (*pcbJ).prev;
			(*(*blocked).tail).next = NULL;
		}
		//pcbJ is in middle
		else{
			(*(*pcbJ).prev).next = (*pcbJ).next;
			(*(*pcbJ).next).prev = (*pcbJ).prev;
		}
		(*blocked).count--;
		return 1;
	}
}

/*
 * FIND READY
 * Written by Joseph DeLong and Alex J. Newcomer
 * Debugged by pimp daddy
 * Searches all queues for a process with the given name.
 * Parameters: Process Name
 * Returns:
 *      Pointer to the PCB if found
 *      NULL if error
 */
MPX_PCB* find_ready(char processName[9]) {
	MPX_PCB* temp;
	int found = 0, count = 0, count1 = 0;
	temp = (*ready).head;
	for(count = 0; count<(*ready).count; count++){
		if(!strcmp((*temp).processName,processName)) { //if names match
			return temp;
		}
		temp = (*temp).next;
	}
	return NULL;
}

/*
 * FIND BLOCKED
 * created by Jospeh DeLong & Alex Bouvy
 */
MPX_PCB* find_blocked(char processName[9]) {
	MPX_PCB* temp;
	int found = 0, count = 0, count1 = 0;
	temp = (*blocked).head;
	for(count = 0; count<(*blocked).count; count++){
		if(!strcmp((*temp).processName,processName)) { //if names match
			return temp;
		}
		temp = (*temp).next;
	}
	return NULL;
}

/*
 * BLOCK PCB
 * created by Alex J. Newcomer
 */
void blockPCB(char processName[9]){
	MPX_PCB* temp;
	processName[strlen(processName)] = '\0';
	temp = find_ready(processName);
	if(temp == NULL){
		temp = find_blocked(processName);
		if(temp == NULL){
			printf("%s doesn't exist.\n", processName);
		} else {
			printf("%s is already blocked.\n", processName);
		}
	} else {
		printf("'%s' blocked.\n",processName);
		removePCB(temp, 1);
		insert_blocked(temp);
	}
}

/*
 * UNBLOCK PCB
 * created by Alex J. Newcomer
 */
void unblockPCB(char processName[9]){
	MPX_PCB* temp;
	processName[strlen(processName)- 1] = '\0';
	temp = find_ready(processName);
	if(temp == NULL){
		temp = find_blocked(processName);
		if(temp == NULL){
			printf("%s doesn't exist.\n", processName);
		} else {
			printf("'%s' unblocked.\n",processName);
			removePCB(temp, 0);
			insert_ready(temp);
		}
	} else {
		printf("%s is already ready.\n", processName);
	}
}
/*
 * LOGO function
 * Written by Joseph DeLong
 * Displays an animated ASCII logo of a running horse, as well as a final load screen, with the name of the OS
 * parameters: NONE
 * returns: an Integer representing either 0 (normal operation/termination) or a non-zero number (error code)
 */
int logo(void) {
	//open all logo files
	int h,i,j,k;
	FILE *frame01 = fopen("Frame01","r");
	FILE *frame02 = fopen("Frame02","r");
	FILE *frame03 = fopen("Frame03","r");
	FILE *frame04 = fopen("Frame04","r");
	FILE *frame05 = fopen("Frame05","r");
	FILE *frame06 = fopen("Frame06","r");
	FILE *frame07 = fopen("Frame07","r");
	FILE *frame08 = fopen("Frame08","r");
	FILE *frame09 = fopen("Frame09","r");
	FILE *frame10 = fopen("Frame10","r");
	FILE *frame11 = fopen("Frame11","r");
	FILE *frameF = fopen("FrameF","r");
	//make FILE array
	FILE *frames[11];
	frames[0] = frame01;
	frames[1] = frame02;
	frames[2] = frame03;
	frames[3] = frame04;
	frames[4] = frame05;
	frames[5] = frame06;
	frames[6] = frame07;
	frames[7] = frame08;
	frames[8] = frame09;
	frames[9] = frame10;
	frames[10] = frame11;
	//set up for iteration
	for (h = 0; h < 4; h++) { //number of animations
		//set seek position to start of files
		fseek(frame01,0,SEEK_SET);
		fseek(frame02,0,SEEK_SET);
		fseek(frame03,0,SEEK_SET);
		fseek(frame04,0,SEEK_SET);
		fseek(frame05,0,SEEK_SET);
		fseek(frame06,0,SEEK_SET);
		fseek(frame07,0,SEEK_SET);
		fseek(frame08,0,SEEK_SET);
		fseek(frame09,0,SEEK_SET);
		fseek(frame10,0,SEEK_SET);
		fseek(frame11,0,SEEK_SET);
		for(i = 0; i < 11; i++) { //number of frames
			for(j = 0; j < 25; j++) { //number of rows in each frame
				for(k = 0; k < 80; k++) { //number of characters in each row
					printf("%c", fgetc(frames[i]));
				}
				fgetc(frames[i]);//this should clear the newline character from being captured
			}
			delay(125); //wait for 1/8th of a second after each frame <dos.h>
		}
	}
	//display final load screen
	fseek(frameF,0,SEEK_SET);
	for(j = 0; j < 25; j++) { //number of rows
		for(k = 0; k < 80; k++) { //number of characters in each row
			printf("%c", fgetc(frameF));
		}
		fgetc(frameF);//this should clear the newline character from being captured
	}
	delay(3000); //wait 3 seconds <dos.h>
	//close all logo files
	fclose(frame01);
	fclose(frame02);
	fclose(frame03);
	fclose(frame04);
	fclose(frame05);
	fclose(frame06);
	fclose(frame07);
	fclose(frame08);
	fclose(frame09);
	fclose(frame10);
	fclose(frame11);
	fclose(frameF);
	//exit
	return 0;
}

/*
 *ALIAS
 *Changes name of a function specified by user
 *Alex Bouvy
 */
void alias(char* fname, char* newname, char** cnames) {
	int i;
	int errCode = 0;
	int notFound = 0;
	newname[strlen(newname)- 1] = '\0';
	for(i = 0; i<40; i++){
		if(!strcmp(cnames[i],newname)){
			errCode = 999;
		}
	}
	if(!errCode){
		for(i = 0; i<40; i++){
			if(!strcmp(cnames[i],fname)){
				strcpy(cnames[i],newname);
				return;
			}
			notFound = 999;
		}
	}
	else printf("Operation not performed, command names must be unique.\n");
	if(notFound) printf("Command '%s' not found.\n",fname);
}

//--------------------------------------------------------/R2 COMMANDS---------------------------------------------------------//

//---------------------------------------------------------R3 COMMANDS---------------------------------------------------------//

/*
 * sys_call()
 * Is the handler called by the system when the int 60h instruction is encountered.
 * Saves the state of the currently operating process, and calls dispatch() to get the next process.
 * parameters: NONE
 * returns: nothing
 */
void interrupt sys_call() {
	//Update stack top IS THIS CORRECT?
	cop->stack_top = (unsigned char*)MK_FP(_SS,_SP);
	//Access parameters that sys_req() placed on the stack for us:
	param_ptr = ( param*)(cop->stack_top + sizeof(context));
	//Switch to temporary stack:
	new_ss = FP_SEG(sys_stack);
	new_sp = FP_OFF(sys_stack) + SYS_STACK_SIZE;
	_SS = new_ss;
	_SP = new_sp;
	trm_getc();
	//begin
	if(termIOCB->eventFlag == 1){
		termIOCB->eventFlag = 0;
		dummy1 = termIOCB->head;
		termIOCB->head = dummy1->next;
		termIOCB->length--;
		//removed iod at head of iocb queue
		dummy = dummy1->requestingProcess;
		//unblock iod and place it in the ready queue
		dummy->pcb_state = READY;
		removePCB(dummy, 0 );
		insert_ready(dummy);
		//process the terminal io requests if there are any
		if(termIOCB->head != NULL){
			if(termIOCB->head->IORequestType == READ){
				trm_read(termIOCB->head->buff, termIOCB->head->buffCount);
			} else if (termIOCB->head->IORequestType == WRITE){
				trm_write(termIOCB->head->buff, termIOCB->head->buffCount);
			} else if (termIOCB->head->IORequestType == CLEAR){
				trm_clear();
			} else if  (termIOCB->head->IORequestType == GOTOXY){
				trm_gotoxy(0, 0);
			}
		}
	}
	//check com for IO
	else if(comPortIOCB->eventFlag == 1){
		comPortIOCB->eventFlag = 0;
		dummy1 = comPortIOCB->head;
		comPortIOCB->head = dummy1->next;
		comPortIOCB->length--;
		dummy = dummy1->requestingProcess;
		dummy->pcb_state = READY;
		removePCB(dummy, 0 );
		insert_ready(dummy);
		if(comPortIOCB->head != NULL){
			if(dummy1->IORequestType == READ){
				com_read(comPortIOCB->head->buff, comPortIOCB->head->buffCount);
			} else if (dummy1->IORequestType == WRITE){
				com_write(comPortIOCB->head->buff, comPortIOCB->head->buffCount);
			}		
		}
		//end
	}
	//Check parameters:
	if((*param_ptr).op_code == IDLE) {
		(*cop).pcb_state = READY; //set cop -> state to ready
		insert_ready(cop); //insert cop into ready queue
	}
	if((*param_ptr).op_code == EXIT) {
		sys_free_mem(cop->stack_base);
		freePCB(cop); //delete cop and free its memory
		cop = NULL; //set cop = null
	}
	if((*param_ptr).op_code == READ) {
		IOSched();
	}
	if((*param_ptr).op_code == WRITE) {
		IOSched();
	}
	if((*param_ptr).op_code == GOTOXY){
		IOSched();
	}
	if((*param_ptr).op_code == CLEAR){
		IOSched();
	}
	dispatcher();
}

/*
 * dispatcher()
 * Alex Newcomer
 * Prepares the first process of the ready queue for execution by switching to its stack.
 * parameters: NONE
 * returns: nothing
 */
void interrupt dispatcher() {
	flagyyflaggedyflag = 0;
	if(ss_save == NULL){
		ss_save = _SS;
		sp_save = _SP;
	}
	dummy = ready->head;
	for(iglobal = 0; iglobal < (*ready).count; iglobal++){
		if(!(dummy->isSuspended)){
			//found the first non suspended pcb on the ready queue.
			flagyyflaggedyflag = 1;
			cop = dummy;
			whyreturnaninthere = removePCB( cop, 1);
			cop->pcb_state = RUNNING;
			new_ss = FP_SEG(cop->stack_top);
			new_sp = FP_OFF(cop->stack_top);
			break;
		}
		dummy = dummy->next;
	}
	if(!flagyyflaggedyflag){
		cop = NULL;
		new_ss = ss_save;
		new_sp = sp_save;
		sp_save = NULL;
		ss_save = NULL;
	}
	_SS = new_ss;
	_SP = new_sp;
}

/*
 * load_procs
 * Written by: Joseph DeLong
 */
void load_procs(void) {
	int i;
	MPX_PCB* tests[5];
	context* contexts[5];
	tests[0] = setupPCB("test0001", 1, 0);
	tests[1] = setupPCB("test0002", 1, 0);
	tests[2] = setupPCB("test0003", 1, 0);
	tests[3] = setupPCB("test0004", 1, 0);
	tests[4] = setupPCB("test0005", 1, 0);
	contexts[0] = (context*) tests[0]->stack_top;
	contexts[1] = (context*) tests[1]->stack_top;
	contexts[2] = (context*) tests[2]->stack_top;
	contexts[3] = (context*) tests[3]->stack_top;
	contexts[4] = (context*) tests[4]->stack_top;
	contexts[0]->IP = FP_OFF(&test1_R3);
	contexts[0]->CS = FP_SEG(&test1_R3);
	contexts[0]->FLAGS = 0x200;
	contexts[0]->DS = _DS;
	contexts[0]->ES = _ES;
	insert_ready(tests[0]);
	contexts[1]->IP = FP_OFF(&test2_R3);
	contexts[1]->CS = FP_SEG(&test2_R3);
	contexts[1]->FLAGS = 0x200;
	contexts[1]->DS = _DS;
	contexts[1]->ES = _ES;
	insert_ready(tests[1]);
	contexts[2]->IP = FP_OFF(&test3_R3);
	contexts[2]->CS = FP_SEG(&test3_R3);
	contexts[2]->FLAGS = 0x200;
	contexts[2]->DS = _DS;
	contexts[2]->ES = _ES;
	insert_ready(tests[2]);
	contexts[3]->IP = FP_OFF(&test4_R3);
	contexts[3]->CS = FP_SEG(&test4_R3);
	contexts[3]->FLAGS = 0x200;
	contexts[3]->DS = _DS;
	contexts[3]->ES = _ES;
	insert_ready(tests[3]);
	contexts[4]->IP = FP_OFF(&test5_R3);
	contexts[4]->CS = FP_SEG(&test5_R3);
	contexts[4]->FLAGS = 0x200;
	contexts[4]->DS = _DS;
	contexts[4]->ES = _ES;
	insert_ready(tests[4]);
}

//--------------------------------------------------------/R3 COMMANDS---------------------------------------------------------//
// lots of dashes r4 commands lots more dashes

/*
 * LOAD PROGRAM
 * Written by: Justin Hamric, Alex Newcomer
 */
void load_program(char dirName[40], char programName[9], int priority){
	int SCP, LProg;
	int prog_len_p;//program length in bytes
	int start_offset_p;//
	MPX_PCB *pcb;
	context *pcbContext;
	//check args
	//NOTE IF PRIO NOT INCLUDED DEFAULT TO 0
	if(priority >= -128 && priority <= 127){
		if((find_ready(programName) == NULL)&&(find_blocked(programName) == NULL)){
			//check program
			SCP = sys_check_program(dirName, programName, &prog_len_p, &start_offset_p);
			if(SCP == 0){
				printf("Valid Program\n");
				pcb = sys_alloc_mem(sizeof(MPX_PCB));
				pcb->stack_base = sys_alloc_mem(SYS_STACK_SIZE);
				pcb->stack_top = pcb->stack_base + SYS_STACK_SIZE-sizeof(context);
				strcpy(pcb->processName,programName);
				strcat(pcb->processName,"\0");
				pcb->processID = 0;
				pcb->processClass = 1; //system is 0, application is 1
				pcb->priority = priority;
				pcb->pcb_state = 1;
				pcb->isSuspended = 1;
				pcb->memorySize = prog_len_p;
				pcb->load_address = (unsigned char*)sys_alloc_mem(prog_len_p);
				pcb->exec_address = pcb->load_address + start_offset_p;
				//initialize context area of stack
				pcbContext = (context *) pcb->stack_top; //link the context to the stack
				pcbContext->IP = FP_OFF(pcb->exec_address); //set the offset for IP and FP based on the exec address computed above
				pcbContext->CS = FP_SEG(pcb->exec_address);
				pcbContext->FLAGS = 0x200;
				pcbContext->DS = _DS;
				pcbContext->ES = _ES;
				LProg = sys_load_program(pcb->load_address, pcb->memorySize, dirName, programName);
				if(LProg == 0){
					printf("Program Loaded\n");
					printf("Inserting into ready\n");
					insert_ready(pcb);
				} else {
					printf("Program did NOT load. Error %d\n", LProg);
				}
			} else if(SCP == ERR_SUP_NAMLNG){
				printf("Could not load program: name was too long!\n");//print error
			} else if(SCP == ERR_SUP_FILNFD){
				printf("Could not load program: File specified was not found.\n");//print error
			} else if(SCP == ERR_SUP_FILINV){
				printf("Could not load program: File contents not a valid program.\n");//print error
			}
		} else {
			printf("Process already exists\n");
		}
	} else {
		printf("Priority is invalid\n");
	}
}

/*
 * TERMINATE PROCESS
 * Written by: Justin Hamric
 */
void terminate_process(char processName[9]){
	MPX_PCB* newpcb;
	newpcb = find_ready(processName);
	if(newpcb != NULL){//if a pcb is found in the ready queue, delete
		if(newpcb->processClass == 0){
			printf("PCB '%s' is a system function and cannot be deleted.\n", processName);
		}else{
			removePCB(newpcb, 1);
			sys_free_mem(newpcb->load_address);
			sys_free_mem(newpcb->stack_base);
			freePCB(newpcb);
			printf("PCB '%s' deletion successful.\n",processName);
		}
	} else{  //atempt to find in blocked queue
		newpcb = find_blocked(processName);
		if(newpcb != NULL){//if found in blocked delete it
			if(newpcb->processClass == 0){
				printf("PCB '%s' is a system function and cannot be deleted.\n", processName);
			}else{
				removePCB(newpcb, 0);
				sys_free_mem(newpcb->load_address);
				sys_free_mem(newpcb->stack_base);
				freePCB(newpcb);
				printf("PCB '%s' deletion successful.\n",processName);
			}
		} else printf("PCB not found.\n");
	}
}

// some slashes/r4 commands a few more slashes //
// lots more slashes// r6 commands // slashes galore//

/*
 * R6Init
 * Written By Alex J. Newcomer
 */
void R6Init(){
	//setup io control block
	termIOCB = (struct MPX_IOCB*)sys_alloc_mem(sizeof(struct MPX_IOCB));
	termIOCB->eventFlag = 0;
	termIOCB->length = 0;
	termIOCB->tail = NULL;
	termIOCB->head = NULL;
	//setup com port io control block
	comPortIOCB = (struct MPX_IOCB*)sys_alloc_mem(sizeof(struct MPX_IOCB));
	comPortIOCB->eventFlag = 0;
	comPortIOCB->length = 0;
	comPortIOCB->head = NULL;
	comPortIOCB->tail = NULL;	
}

/*
 * I/O SCHEDULER
 * Written by: Joseph DeLong
 * Debugged by: Alex Newcomer, Alex Bouvy, Justin Hamric
 *	The I/O scheduler is a function that processes a new I/O request.
 *		In short, the I/O scheduler creates a new IOD for the I/O
 *		request, and either runs it if the device is ready, or
 *		places it in the waiting queue to be run later.
 */
void IOSched(void) {
	struct MPX_IOD *tempIOD; //temp storage for new IO Request Descriptor
	tempIOD = (struct MPX_IOD*)sys_alloc_mem(sizeof(struct MPX_IOD)); //allocate memory for temp
	tempIOD->deviceName = param_ptr->device_id; //set which device is being requested
	tempIOD->requestingProcess = cop; //set IOD's PCB to Currently Operating Process
	tempIOD->buff = param_ptr->buf_p; //set IOD's buffer to parameter's buffer
	tempIOD->buffCount = param_ptr->count_p; //set IOD's buffer count to param's count
	tempIOD->IORequestType = param_ptr->op_code; //set operation type to param op code
	if(tempIOD->deviceName == TERMINAL) { //if device is TERMINAL
		if(termIOCB->length == 0) { //If the waiting queue for terminal is empty
			termIOCB->head = tempIOD;//Insert the new IOD into the waiting queue as the head and tail
			termIOCB->tail = tempIOD;
			termIOCB->length=1; //set count to 1
			// Process the request immediately
			if(tempIOD->IORequestType == 0) { //if process wants to IDLE
				//IDLE
			}
			else if(tempIOD->IORequestType == READ) { //if process wants to READ
				trm_read(termIOCB->head->buff,termIOCB->head->buffCount); //READ
			}
			else if(tempIOD->IORequestType == WRITE) { //if process wants to WRITE
				trm_write(termIOCB->head->buff,termIOCB->head->buffCount); //WRITE
			}
			else if(tempIOD->IORequestType == CLEAR) { //if process wants to CLEAR
				trm_clear(); //CLEAR
			}
			else if(tempIOD->IORequestType == GOTOXY) { //if process wants to GOTOXY
				trm_gotoxy(atoi(trm_getc()),atoi(trm_getc())); //GOTOXY
			}
			else if(tempIOD->IORequestType == EXIT) { //if process wants to ExIT
				trm_close(); //EXIT
			}
		}
		else { //wait queue for TERMINAL not empty
			termIOCB->tail->next = tempIOD;
			tempIOD->next = NULL;
			termIOCB->tail = tempIOD;// Insert the new IOD into the waiting queue at the tail
			termIOCB->length++;
		}
	}
	if(tempIOD->deviceName == COM_PORT) { //if device is COM_PORT

		if(comPortIOCB->length == 0) { //if waiting queue for com port is empty
			comPortIOCB->head = tempIOD;// Insert the new IOD into the waiting queue as the head and tail
			comPortIOCB->tail = tempIOD;
			comPortIOCB->length = 1; //set count to 1
			// Process the request immediately
			if(tempIOD->IORequestType == IDLE) { //if process wants to IDLE
				//IDLE
			}
			else if(tempIOD->IORequestType == READ) { //if process wants to READ
				com_read(comPortIOCB->head->buff,comPortIOCB->head->buffCount); //READ
			}
			else if(tempIOD->IORequestType == WRITE) { //if process wants to WRITE
				com_write(comPortIOCB->head->buff,comPortIOCB->head->buffCount); //WRITE
			}
			else if(tempIOD->IORequestType == CLEAR) { //if process wants to CLEAR
				//CLEAR
			}
			else if(tempIOD->IORequestType == GOTOXY) { //if process wants to GOTOXY
				//GOTOXY
			}
			else if(tempIOD->IORequestType == EXIT) { //if process wants to EXIT
				com_close(); //EXIT
			}
		}
		else { //wait queue for com port not empty
			comPortIOCB->tail->next = tempIOD;
			tempIOD->next = NULL; //unlink it
			comPortIOCB->tail = tempIOD;// Insert the new IOD into the waiting queue at the tail
			comPortIOCB->length++;
		}
	}
	cop->pcb_state = BLOCKED;
	blockPCB(cop->processName);//block the process and return
	return;
}

// end r6 commands // slashes //
